============================================================================
Dragon Flight Simulator by François Vander Linden
============================================================================

This is called "Dragon Flight Simulator over Tolkien's Mountain Of Fire: A Teaser".
Use the joystick to maneuver your tamed dragon as you approach the dreaded Moutain Of Fire.
Push the joystick forward to accelerate and pull it to decelerate and flight backwards (yes, your dragon is equipped with a reversing assistance system). Turn left or right and enjoy the scenery sliding on the horizon !
Of course, as this is a teaser, you never get to reach the Mountain Of Fire (you'll have to buy the full game when it's released). Your only option is to flight backwards and then return as many times as you want.

Technical notes:
---------------
There's no special technique here: it's several HPLOTs using page flipping and very basic trigonometry.
BUT of course, as my description implies, I cheated ...
A LOT !!!
There's no line clipping for example. That means you can't go too far to the left or to the right and see the mountain being clipped on a side of the screen. That's why you can't approach the mountain too much and also why you can't make you dragon do a full roll.
The other cheat is that it's not really 3D (although there are a few COS/SIN calls). In a real 3D world, you are moving and the objects are drawn according to your point of view. In this world, the mountain is moving within your fixed point-of-view.
The moutain is moving from left to right on your horizon line and while you approach its height is modified so it looks like it's "growing" ...
As a nice feature/bonus, the program uses HGR page flipping, so there's no flickering. All in all the result for an Applesoft 2-liner is almost as smooth as the original "Flight Simulator" back in the day. Not too bad, I guess.
Here's the 2-liner, followed by the "unfolded" 2 lines-code with explanation for each statement. A DSK will follow.
Enjoy the illusion !

CODE EXPLANATION
----------------
The mountain is represented by three points in variables C,D (lower left point/side), A,B (peak) and E,F (lower right point/side).
Each page is using the identicaly named arrays A(), B(), C(), D(), E(), F() to store the previously drawn values on each page.
At first (A,B) is considered to be centered on the screen but just vertically above (140,80).
The base center location of the mountain is stored in variables (P,Q). This is the point right vertically below the peak ON the horizon line.
All the values are carefully selected so that line clipping is not needed. For example, if the mountain were to exceed height 40, the program would soon crash. The same would happen if the mountain's lower left and right points were drawn farther than 80 pixels from the center of the screen.
0 HGR : REM We are going to use page flipping, so we need to clear both hires pages first.
1 HGR2 : REM We will use hires page 2 as our first drawing page because it's full screen. If we had inverted those first two statements I would have had to make a POKE 49234,0 to hide the 4-lines of (garbled) text of page 2 and wasted 11 characters.
2 W = 159: REM This is the Y high limit of the screen (even though we're using page 2 we use the limits of page 1)
3 V = 80: REM This is the reference Y position of the center base of the mountain. It's also the center Y-coord of the screen.
5 K = 279: REM This is the X high limit of the screen
6 L = 140: REM this is the reference X position of the center base of the moutain. It's also the center X-coord of the screen.
7 G = 2: REM this is the page number we're working on. We're working on page number 2. At first I had numbered those using 0-1 but it was a bad idea (see below)
8 FOR I = 0 TO 9E9: REM this is (almost) an infinite loop. 9E9 meaning 9x10e9. Believe me you'll not see the end of it. Usually I use a FOR I = 0 TO 1 loop and modify I to zero just before the final NEXT but this technique saved a few chars.
9 Y = PDL (0) * W / 255: REM we read the roll value from 0-159
10 POKE 230,G * 32: REM this POKE indicates that all HPLOT will occur on page G. My first formula was POKE 230, 32+G*32 with G from 0-1. It wasted 3 characters. And that's A LOT (when you write a 2-liner).
11 HCOLOR= 0: REM We set color to black #1 because we're going to erase what has been drawn before (on the first iteration it doesn't matter)
12 HPLOT 0,W - Y(G) TO K,Y(G): REM we erase the previous horizon line using the previously stored value of Y ("roll"). As you can see the horizon is centered on the (HGR1) screen because we plot from 0,W-(previous Y) to 279,(previous Y). So the horizon always passes through (140,80) (or 139,79 or whatever the approximation is)
13 HPLOT C(G),D(G) TO A(G),B(G) TO E(G),F(G): REM we erase the mountain using previously stored coordinates. All these variables are equal to zero on the first pass and it justs plots black pixels into (0,0), so the first pass doesn't count ...
14 R = - .96 * (W - 2 * Y) / K: REM the part aftet the ".96*" is the slope of the horizon in %. This is pretty basic math but we have to apply a factor of .96 to accomodate some kind of imprecision (? I don't know exactly why !). This factor should have been the conversion from % to radiants (for a right angle) but it didn't really worked.
15 Z = Z - (Y - V) / 4: REM Z will hold a value from -80 to 80 indicating the drift of the mountain. The actual drift is added by a value depending of the "roll" (Y) and its center value (which happen to be 80 ! that is, V), divided by 4 so it doesn't drift too fast.
16 Z = Z * (Z > - V AND Z < V) - V * (Z < = - V) + V * (Z > = V): REM this formula ensures Z is between -80 and 80 (V and -V). It's 3 "IF"s concatenated in 3 additions. The first part means Z remains Z if Z is between -V and V (-80 and 80), if it's not then this part equals ZERO. In all cases this is added to the second part which specifies you have to add -V (-80) if Z is below or equal to -V (if not then it's zero). Then comes the last part that says you have to add V (80) if Z>=V. In the end it reads: Z = Z if between -80 and 80 if not 0, plus -V if Z<=-V, if not zero, plus +V if Z>=V, if not zero. As all conditions are exclusive, only one of the parts is different than zero and is stored in Z.
17 S = SIN (R):O = COS (R): REM We hold the values for the sine and cosine of the slope in S and O
18 HCOLOR= 3: REM setting color to white #1
19 P = L + O * Z: REM P is the X position of the center base of the mountain ON THE horizon. Notice that the drift is used as a radius AND that our point of reference is the center of the screen (L,V)
20 Q = V + S * Z: REM Q is the Y position of the center base of the moutain ON THE horizon
21 A = P + S * H: REM From the center base we compute the X-coord of the peak. H is the height. At first is zero. Y-axis of the joystick will modify it.
22 B = Q - O * H: REM same for the Y-coord
23 T = - 20 - H + Z: REM T is a temp variable that will help compute the lower left point of the mountain. It's basically the "drift" (Z) minus the height and an additional 20 (for good measure -- this is completely arbitrary)
24 C = L + O * T: REM the lower left point is computed using T as radius from the center of the screen. This is the X-coord
25 D = V + S * T: REM and this is the Y-coord.
26 T = 20 + H + Z: REM we do it again for the right lower point.
27 E = L + O * T: REM X-coord of that point
28 F = V + S * T: REM Y-coord of that point
29 HPLOT 0,W - Y TO K,Y: REM We now draw the horizon line using our "freshest" values
30 HPLOT C,D TO A,B TO E,F: REM and the mountain
31 Y(G) = Y:A(G) = A:B(G) = B:C(G) = C:D(G) = D:E(G) = E:F(G) = F: REM we save every computed coordinate in arrays using the page as index. Those will be used in the next-next iteration to erase what we just plotted.
32 H = H - ( PDL (1) - L) / 64: REM What's going to be the next height (H) of the mountain ? This depends on the value of the PDL(1). A division by 64 reduces our "dragon speed" and the way that H is actually impacted.
33 H = H * (H < = 40 AND H > = 0) + 40 * (H > 40): REM We make sure H is between 0 and 40.
34 POKE 49235 + G,0: REM We now display the page "G" and ...
35 G = 3 - G: REM we flip the page variable ... 1 becomes 2 and 2 becomes 1. Line 10 will actually tell Applesoft we work on that page from now on while the other page is displayed. That POKE in line 10 should have been here logically but then the optimized code would have had a second line too long. So it was moved at the start of the loop because the first line could hold a few more chars.
36 NEXT : REM our "almost-infinite" loop